/**
 * 
 * @param canvas 
 * @param {Number} xPosition
 * @param {Number} yPosition
 * @param {Number} radius 
 * @param {String} gender Can be "M", "F" or "U"
 * @param {Number} startAngle 
 * @param {Number} endAngle
 * @param {String} color CSS color
 * @return {Raphael.el}
 */
function sector(canvas, xPosition, yPosition, radius, gender, startAngle, endAngle, color) {
    var sectorPath,
        gen = gender,
        cx = xPosition,
        cy = yPosition,
        r = radius,
        paper = canvas,
        rad = Math.PI / 180,
        shapeAttributes = {fill: color, 'stroke-width':.0 };

    var circleCoordinate = function(alpha) {
            var x = cx + r * Math.cos(-alpha * rad),
                y = cy + r * Math.sin(-alpha * rad);
            return [x,y];
        };

    if (gen === 'F') {
        if(endAngle-startAngle == 360)
        {
            return paper.circle(cx, cy, r).attr(shapeAttributes);
        }
        var x1 = circleCoordinate(startAngle)[0],
            x2 = circleCoordinate(endAngle)[0],
            y1 = circleCoordinate(startAngle)[1],
            y2 = circleCoordinate(endAngle)[1];

        return paper.path(["M", cx, cy, "L", x1, y1, "A", r, r, 0, +(endAngle - startAngle > 180), 0, x2, y2, "z"]).attr(shapeAttributes);
    }
    else if(gen === 'M') {
        function sideAtAngle(angle) {
            return (((angle + 45)/90).floor()) % 4;
        }

        function tanOfDegrees(degrees) {
            var radians = degrees * Math.PI/180;
            return Math.tan(radians);
        }

        function getCoord(alpha) {
            var side = sideAtAngle(alpha);
            var result = {};
            var xFactor = (side % 2);
            var yFactor = (1 - side % 2);
            var sideFactor = side % 3 ? -1 : 1;

            result.angle = (alpha - side * 90 - ((side == 0 && alpha > 45) ? 360 : 0)) * (side < 2 ? -1 : 1);
            var d = r * tanOfDegrees(result.angle);
            result.x = cx + xFactor * d + yFactor * sideFactor * r;
            result.y = cy + yFactor * d + xFactor * sideFactor * r;
            return result;
        }

        function getNextCorner(side) {
            var factorA = (side % 3) ? -1: 1,
                factorB = (side < 2) ? -1: 1,
                result = {};
            result.x = cx + factorA * r;
            result.y = cy + factorB * r;
            return result;
        }

        var startSide = sideAtAngle(startAngle),
            endSide = sideAtAngle(endAngle);
            if(endSide == 0 && endAngle > startAngle) {
                endSide = (startAngle >= 315) ? 0 : 4;
            }
            var numSides = endSide - startSide;

        var startCoord = getCoord(startAngle),
            endCoord = getCoord(endAngle),
            sectorPathData = ["M", endCoord.x, endCoord.y, "L", cx, cy, "L", startCoord.x, startCoord.y],
            currentSide = startSide;

        while(numSides > 0)
        {
            sectorPathData.push("L", getNextCorner(currentSide).x + " " + getNextCorner(currentSide).y);
            currentSide = (++currentSide) % 4;
            numSides--;
        }
        sectorPathData.push("L",endCoord.x, endCoord.y, "z");
        return paper.path(sectorPathData).attr(shapeAttributes);
    }
    else {
        var shape = sector(paper, cx, cy, r* (Math.sqrt(3)/2), "M", startAngle, endAngle, color);
        shape.transform(["...r-45,", cx , cy]).attr(shapeAttributes);
        return shape;
    }
}

/**
 *
 * @method generateOrb
 * @param canvas Raphael paper
 * @param {Number} x 
 * @param {Number} y 
 * @param {Number} r 
 * @param {Number} hue Hue value between 0 and 1
 * @return {Raphael.st}
 */
function generateOrb (canvas, x, y, r, gender, typetext, type) {
	
	var typetext = typetext;
	var _type = type;
    if (!gender || gender == 'F') {
        var rr = (r-1) * 0.9;
        return canvas.set(
                canvas.rect(x-rr+ 7, y-rr, r*1.5, r*1.5, 0).attr({stroke: "none", fill: "#48ad47", opacity: 1,}),
				canvas.rect(x-rr+ 7, y-rr, r*1.5, r*1.5, 1).attr({stroke: "none", fill: "#48ad47", opacity: 1})
                //chen.yuguo  修改添加兄妹
                //canvas.text(x-rr-10, y+25, typetext).attr({"fill":"#000","font-size":"14px", "font-weight":"500", "text-anchor":"start"})
                
            );
    }

    if (gender == "M") {
        var rr = (r-1) * 0.9;
        return canvas.set(

        			canvas.rect(x-rr+ 3, y-rr, r*1.5, r*1.5, 0).attr({stroke: "none", fill: "#48ad47", opacity: 1,}),
          	    canvas.rect(x-rr+ 3, y-rr, r*1.5, r*1.5, 1).attr({stroke: "none", fill: "#48ad47", opacity: 1})
                //chen.yuguo  修改添加兄妹
                //canvas.text(x-rr-15, y+25,typetext).attr({"fill":"#000","font-size":"14px","font-weight":"500", "text-anchor":"start"})
                
            );
    }
    if (gender == "U") {
        var rr = (r-1) * 0.9;
        return canvas.set(        	
                canvas.rect(x-rr + 4, y-10, r*1.5, r*1.5, 0).attr({stroke: "none", fill: "#48ad47", opacity: 1,}),
                canvas.rect(x-rr + 4, y-10, r*1.5, r*1.5, 1).attr({stroke: "none", fill: "#48ad47", opacity: 1,})
                //chen.yuguo  修改添加兄妹
                //canvas.text(x+rr-10, y+25, typetext).attr({"fill":"#000","font-size":"14px","font-weight":"500", "text-anchor":"middle"})
                
            );
    }
}
//添加兄妹，坐标跑偏重新方法，chen.yuguo
function generateOrb22 (canvas, x, y, r, gender, typetext, type) {
    
    var typetext = typetext;
    var _type = type;
    if (!gender || gender == 'F') {
        var rr = (r-1) * 0.9;
        return canvas.set(
               canvas.text(x-rr-10, y+25, typetext).attr({"fill":"#000","font-size":"20px", "font-weight":"500", "text-anchor":"start"})
                
            );
    }

    if (gender == "M") {
        var rr = (r-1) * 0.9;
        return canvas.set(

                 canvas.text(x-rr-15, y+25,typetext).attr({"fill":"#000","font-size":"20px","font-weight":"500", "text-anchor":"start"})
                
            );
    }
    if (gender == "U") {
        var rr = (r-1) * 0.9;
        return canvas.set(          
                canvas.text(x+rr-10, y+25, typetext).attr({"fill":"#000","font-size":"20px","font-weight":"500", "text-anchor":"middle"})
                
            );
    }
}
function drawCornerCurve (xFrom, yFrom, xTo, yTo, bendDown, attr, doubleCurve, shiftx1, shifty1, shiftx2, shifty2 ) {
    var xDistance = xTo - xFrom;
    var yDistance = yFrom - yTo;

    var dist1x = xDistance/2;
    var dist2x = xDistance/10;
    var dist1y = yDistance/2;
    var dist2y = yDistance/10;

    var curve;

    if (bendDown) {
        var raphaelPath =  "M " + (xFrom)          + " " + (yFrom) +
                          " C " + (xFrom + dist1x) + " " + (yFrom + dist2y) +
                            " " + (xTo   + dist2x) + " " + (yTo   + dist1y) +
                            " " + (xTo)            + " " + (yTo);
        curve = editor.getPaper().path(raphaelPath).attr(attr).toBack();
    } else {
        var raphaelPath =   "M " + (xFrom)          + " " + (yFrom) +
                           " C " + (xFrom - dist2x) + " " + (yFrom - dist1y) +
                             " " + (xTo   - dist1x) + " " + (yTo   - dist2y) +
                             " " + (xTo)            + " " + (yTo);
        curve = editor.getPaper().path(raphaelPath).attr(attr).toBack();
    }

    if (doubleCurve) {
        var curve2 = curve.clone().toBack();
        curve .transform("t " + shiftx1  + "," + shifty1 + "...");
        curve2.transform("t " + shiftx2 + "," + shifty2 + "...");
    }
}

function drawLevelChangeCurve (xFrom, yFrom, xTo, yTo, attr, doubleCurve, shiftx1, shifty1, shiftx2, shifty2 )
{
    var xDistance = xTo - xFrom;
    var dist1x    = xDistance/2;

    var raphaelPath = " M " + (xFrom)           + " " + yFrom;
    raphaelPath    += " C " + (xFrom + dist1x)  + " " + (yFrom) +
                        " " + (xTo   - dist1x)  + " " + (yTo) +
                        " " + (xTo)             + " " + (yTo);

    curve = editor.getPaper().path(raphaelPath).attr(attr).toBack();
    if (doubleCurve) {
        var curve2 = curve.clone().toBack();
        curve .transform("t " + shiftx1  + "," + shifty1 + "...");
        curve2.transform("t " + shiftx2 + "," + shifty2 + "...");
    }
}

function findXInterceptGivenLineAndY(crossY, x1, y1, x2, y2) {
    // y = ax + b
    if (x1 == x2) return x1;
    var a = (y1 - y2)/(x1 - x2);
    var b = y1 - a*x1;
    var interceptX = (crossY - b)/a;
    return interceptX;
}

function getElementHalfHeight(t) {
    return Math.floor(t.getBBox().height/2);
}
	function adjustPreviewWindowHeight (dialogSelectorClass, resizableElementId, minResizableElementHeight, maxResizableElementHeight) {
        var pedigreeDialogue = $$('.'+dialogSelectorClass)[0];
        var resizableElement = $(resizableElementId);
        if (!pedigreeDialogue || !resizableElement) {
            return;
        }
        var screenHeight = window.innerHeight - 10;
        var dialogueHeight = pedigreeDialogue.getHeight();
        var freeSpace = screenHeight - dialogueHeight;
        var resizableElementHeight = resizableElement.getHeight();
        if (freeSpace < 0) {
            var newHeight = Math.max(minResizableElementHeight, resizableElementHeight + freeSpace);
            resizableElement.style.height = newHeight + "px";
        }
        if (freeSpace > 0 && resizableElementHeight < maxResizableElementHeight && resizableElementHeight < resizableElement.scrollHeight) {
            var newHeight = Math.min(maxResizableElementHeight, resizableElementHeight + freeSpace);
            resizableElement.style.height = newHeight + "px";
        }
   }
	
/**
 * @return {Raphael.st}
 */
Raphael.st.flatten = function () {
    var flattenedSet = new Raphael.st.constructor();
        this.forEach(function(element) {
            flattenedSet = flattenedSet.concat(element.flatten());
        });
    return flattenedSet;
};

/**
 * @return {Raphael.st}
 */
Raphael.el.flatten = function () {
    return this.paper.set(this);
};

/**
 * @param {Raphael.st} set
 * @return {Raphael.st}
 */
Raphael.st.concat = function (set) {
    var newSet = this.copy();
    if(typeof(set.forEach) == 'function') {
        set.forEach(function(element) {
            newSet.push(element);
        });
    }
    else {
        newSet.push(set);
    }
    return newSet;
};

/**
 *
 * @param {Raphael.st|Raphael.el} target
 * @return {boolean}
 */
Raphael.st.contains = function (target) {
    var found = false;
    this.forEach(function(element) {
        if(element == target) {
            found = true;
        }
    });
    return found;
};

/**
 * @return {Raphael.st}
 */
Raphael.st.copy = function() {
    var newSet = new Raphael.st.constructor();
    this.forEach(function(element) {
        newSet.push(element);
    });
    return newSet;
};



window.requestAnimFrame = (function(){
    return  window.requestAnimationFrame   ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        window.oRequestAnimationFrame      ||
        window.msRequestAnimationFrame     ||
        function( callback ){
            window.setTimeout(callback, 1000 / 60);
        };
})();